﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using AntJoin.Dapper.Cache;
using AntJoin.Dapper.Mapping;
using System.Reflection;
using System.Threading.Tasks;

namespace AntJoin.Dapper.Session
{
    public class DapperSession : ISqlSession
    {
        public DapperSession(IDao dao)
        {
            _dao = dao;

            //if(ConfigManager.GetRootConfig("DB_ADAPTERS_WATCH")!=null){
            //    XmlChangeWatcher.Instance.Watch(
            //        ConfigManager.GetRootConfig("DB_ADAPTERS_WATCH") );
            //}
        }
        private readonly IDao _dao;
        //public IDao Dao
        //{
        //    get
        //    {
        //        if (dao == null)
        //            throw new System.ArgumentNullException("未指定DapperSession依赖的IDao对象.");
        //        return dao;
        //    }
        //    set { dao = value; }
        //}
        public void TxBegin()
        {
            _dao.TxBegin();
        }
        public void TxRollback()
        {
            _dao.TxRollback();
        }
        public void TxCommit()
        {
            _dao.TxCommit();
        }
        /// <summary>
        /// close connection and commint Tx
        /// </summary>
        public void Close()
        {
            _dao.Close();
        }

        #region 判断该实体是否加入缓存读写

        /// <summary>
        /// 判断该实体是否加入缓存读写
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private TableAttribute IsCacheReadWrite(Type type)
        {
            var props = type.GetTypeInfo().GetCustomAttributes(typeof(TableAttribute), true).ToArray();
            TableAttribute table = null;
            if (props != null && props.Length > 0)
                table = props[0] as TableAttribute;
            if (table != null && table.IsCacheReadWrite)
                return table;
            return null;
        }

        #endregion

        #region 获取主键名称

        /// <summary>
        /// 获取主键名称
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private string GetPrimaryKey(Type type)
        {
            string primaryKey = string.Empty;

            var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.GetProperty);
            foreach (System.Reflection.PropertyInfo p in properties)
            {
                if (p.PropertyType.Namespace.Equals("System") || p.PropertyType.IsEnum())//only primitive types
                {
                    ColumnAttribute col = null;
                    object[] attrs = p.GetCustomAttributes(typeof(ColumnAttribute), false).ToArray();
                    if (attrs.Length > 0) col = attrs[0] as ColumnAttribute;
                    if (col != null)
                    {
                        if (col.IsPrimaryKey)
                        {
                            primaryKey = col.Name;
                            break;
                        }
                    }
                }
            }
            if (primaryKey == string.Empty)
            {
                throw new ArgumentException("该表格未设置主键！");
            }
            return primaryKey;
        }

        #endregion

        #region 从redis缓存中移除该数据

        /// <summary>
        /// 从redis缓存中移除该数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        private void DeleteCacheInfo(Type type, object id)
        {
            if (id == null) return;

            bool isDeleted = false;

            var key = type.FullName + "#" + id.ToString();

            if (StackExchangeHelper.KeyExists(key))
            {
                while (!isDeleted)
                {
                    if (StackExchangeHelper.KeyExists(key))
                    {
                        if (StackExchangeHelper.KeyDelete(key))
                        {
                            isDeleted = true;
                        }
                    }
                    else
                        break;
                }
            }
        }

        /// <summary>
        /// 从redis缓存中移除该数据
        /// </summary>
        /// <param name="obj"></param>
        private void DeleteCacheInfo(object obj)
        {
            Type type = obj.GetType();
            string id = String.Empty;
            TableAttribute table = IsCacheReadWrite(type);
            if (table != null)
            {
                var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.GetProperty);
                foreach (System.Reflection.PropertyInfo p in properties)
                {
                    if (p.PropertyType.Namespace.Equals("System") || p.PropertyType.IsEnum())//only primitive types
                    {
                        ColumnAttribute col = null;
                        object[] attrs = p.GetCustomAttributes(typeof(ColumnAttribute), false).ToArray();
                        if (attrs.Length > 0) col = attrs[0] as ColumnAttribute;
                        if (col != null)
                        {
                            if (col.IsPrimaryKey)
                            {
                                id = p.GetValue(obj, null).ToString();
                                break;
                            }
                        }
                    }
                }
                DeleteCacheInfo(type, id);
            }
        }

        /// <summary>
        /// 从redis缓存中移除该组数据
        /// </summary>
        /// <param name="objs"></param>
        private void DeleteCacheInfo<T>(IList<T> objs)
        {
            if (objs == null || objs.Count == 0) return;

            List<object> ids = new List<object>();
            Type type = typeof(T);
            string value = String.Empty;

            TableAttribute table = IsCacheReadWrite(type);

            if (table != null)
            {
                var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.GetProperty);
                foreach (var obj in objs)
                {
                    foreach (System.Reflection.PropertyInfo p in properties)
                    {
                        if (p.PropertyType.Namespace.Equals("System") || p.PropertyType.IsEnum())//only primitive types
                        {
                            ColumnAttribute col = null;
                            object[] attrs = p.GetCustomAttributes(typeof(ColumnAttribute), false).ToArray();
                            if (attrs.Length > 0) col = attrs[0] as ColumnAttribute;
                            if (col != null)
                            {
                                if (col.IsPrimaryKey)
                                {
                                    ids.Add(p.GetValue(obj, null).ToString());
                                    break;
                                }
                            }
                        }
                    }
                }

                foreach (var id in ids)
                {
                    DeleteCacheInfo(type, id);
                }
            }
        }

        #endregion

        #region 从reids缓存中添加数据
        private void SetCacheInfo(Type type, object id, object data, int expireTime)
        {
            if (id == null || data == null) return;

            var key = type.FullName + "#" + id.ToString();

            if (expireTime > 0)
            {
                StackExchangeHelper.Set(key, data, expireTime);
            }
            else
            {
                StackExchangeHelper.Set(key, data);
            }
        }

        private void SetCacheInfo(object obj)
        {
            Type type = obj.GetType();
            TableAttribute table = IsCacheReadWrite(type);
            object id = null;
            if (table != null && table.IsCacheReadWrite)
            {
                var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.GetProperty);
                foreach (System.Reflection.PropertyInfo p in properties)
                {
                    if (p.PropertyType.Namespace.Equals("System") || p.PropertyType.IsEnum())//only primitive types
                    {
                        ColumnAttribute col = null;
                        object[] attrs = p.GetCustomAttributes(typeof(ColumnAttribute), false).ToArray();
                        if (attrs.Length > 0) col = attrs[0] as ColumnAttribute;
                        if (col != null)
                        {
                            if (col.IsPrimaryKey)
                            {
                                id = p.GetValue(obj, null).ToString();
                                break;
                            }
                        }
                    }
                }
                SetCacheInfo(type, id, obj, table.CacheExpireTime);
            }
        }

        private void SetCacheInfo(object id, object obj)
        {
            Type type = obj.GetType();
            TableAttribute table = IsCacheReadWrite(type);
            if (table != null && table.IsCacheReadWrite)
            {
                SetCacheInfo(type, id, obj, table.CacheExpireTime);
            }
        }

        private void SetCacheInfo<T>(IList<T> objs)
        {
            if (objs == null || objs.Count == 0) return;

            Dictionary<object, object> ids = new Dictionary<object, object>();
            Type type = typeof(T);
            string value = String.Empty;

            TableAttribute table = IsCacheReadWrite(type);

            if (table != null)
            {
                var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.GetProperty);
                foreach (var obj in objs)
                {
                    foreach (System.Reflection.PropertyInfo p in properties)
                    {
                        if (p.PropertyType.Namespace.Equals("System") || p.PropertyType.IsEnum())//only primitive types
                        {
                            ColumnAttribute col = null;
                            object[] attrs = p.GetCustomAttributes(typeof(ColumnAttribute), false).ToArray();
                            if (attrs.Length > 0) col = attrs[0] as ColumnAttribute;
                            if (col != null)
                            {
                                if (col.IsPrimaryKey)
                                {
                                    ids.Add(p.GetValue(obj, null).ToString(), obj);
                                    break;
                                }
                            }
                        }
                    }
                }

                foreach (var id in ids.Keys)
                {
                    SetCacheInfo(type, id, ids[id], table.CacheExpireTime);
                }
            }
        }
        #endregion


        #region 删除数据
        /// <summary>
        /// 根据id删除数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Delete<T>(object id)
        {
            if (id == null) return false;

            Type type = typeof(T);

            if (IsCacheReadWrite(type) != null)
            {
                DeleteCacheInfo(type, id);
            }

            MappingInfo info = MappingInfo.GetMappingInfo<T>();
            return _dao.Execute(
                    info.Delete,
                    new Dictionary<string, object>() { { GetPrimaryKey(type), id } }
                ) == 1;
        }

        /// <summary>
        /// 根据id删除数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync<T>(object id)
        {
            if (id == null) return false;

            Type type = typeof(T);

            if (IsCacheReadWrite(type) != null)
            {
                DeleteCacheInfo(type, id);
            }

            MappingInfo info = MappingInfo.GetMappingInfo<T>();
            return await _dao.ExecuteAsync(
                    info.Delete,
                    new Dictionary<string, object>() { { GetPrimaryKey(type), id } }
                ) == 1;
        }


        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public int Delete(Type type, IDictionary<string, object> param)
        {
            var sql = GetDeleteSql(type, param);
            return _dao.Execute(sql, param);
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(Type type, IDictionary<string, object> param)
        {
            var sql = GetDeleteSql(type, param);
            return await _dao.ExecuteAsync(sql, param);
        }

        private string GetDeleteSql(Type type, IDictionary<string, object> param)
        {
            bool hasId = false;
            string primaryKey = GetPrimaryKey(type);
            string sql = MappingInfo.GetSqlStatementByType(type, "Delete");
            sql = sql.Substring(0, sql.IndexOf(" where ", StringComparison.CurrentCultureIgnoreCase) + 7);

            string where = "";

            foreach (string key in param.Keys)
            {
                if ((String.Compare(key, primaryKey, true) == 0))
                {
                    hasId = true;
                    DeleteCacheInfo(type, param[key]);
                }

                where += string.Format(" and {0}={1}{0}", key, StatementParser.PREFIX);
            }
            if (IsCacheReadWrite(type) != null && !hasId)
            {
                throw new ArgumentException("该表格有加入缓存读写，但当前查询信息未包括主键字段！");
            }
            return sql + where.Substring(5);
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool Delete(object obj)
        {
            if (obj == null) return false;

            DeleteCacheInfo(obj);

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Delete");
            return _dao.Execute(sql, obj) == 1;
        }
        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync(object obj)
        {
            if (obj == null) return false;

            DeleteCacheInfo(obj);

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Delete");
            return (await _dao.ExecuteAsync(sql, obj)) == 1;
        }
        #endregion


        #region 插入数据
        /// <summary>
        /// 插入数据
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName">扩展表名称</param>
        /// <returns></returns>
        public bool Insert(object obj, string extTableName = null)
        {
            if (obj == null) return false;

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Insert", extTableName);
            return _dao.Execute(sql, obj) == 1;
        }
        /// <summary>
        /// 插入数据
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName">扩展表名称</param>
        /// <returns></returns>
        public async Task<bool> InsertAsync(object obj, string extTableName = null)
        {
            if (obj == null) return false;

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Insert", extTableName);
            return await _dao.ExecuteAsync(sql, obj) == 1;
        }

        /// <summary>
        /// 插入数据，返回ID
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName"></param>
        /// <returns></returns>
        public bool Insert(object obj, out int lastInsertId, string extTableName = null)
        {
            lastInsertId = -1;
            if (obj == null) return false;

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Insert", extTableName);
            if (_dao.ConnectionManager.ConnectionTypeName.StartsWith("MySql."))
                sql += ";SELECT LAST_INSERT_ID();";

            lastInsertId = _dao.QueryFirstOrDefault<int>(sql, obj);
            if (lastInsertId > 0)
            {
                SetCacheInfo(lastInsertId, obj);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 插入数据，返回ID
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName"></param>
        /// <returns>返回ID</returns>
        public T Insert<T>(object obj, string extTableName = null)
        {
            T d = default;
            if (obj == null) return d;

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Insert", extTableName);
            if (_dao.ConnectionManager.ConnectionTypeName.StartsWith("MySql."))
                sql += ";SELECT LAST_INSERT_ID();";

            var lastInsertId = _dao.QueryFirstOrDefault<T>(sql, obj);
            if (!EqualityComparer<T>.Default.Equals(lastInsertId, d))
            {
                SetCacheInfo(lastInsertId, obj);
            }
            return lastInsertId;
        }

        /// <summary>
        /// 插入数据，返回ID
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName"></param>
        /// <returns></returns>
        public async Task<T> InsertAsync<T>(object obj, string extTableName = null)
        {
            T d = default;
            if (obj == null) return d;
            var t = obj.GetType();
            string sql = MappingInfo.GetSqlStatementByType(t, "Insert", extTableName);
            if (_dao.ConnectionManager.ConnectionTypeName.StartsWith("MySql."))
                sql += ";SELECT LAST_INSERT_ID();";

            var lastInsertId = await _dao.QueryFirstOrDefaultAsync<T>(sql, obj);
            if (!EqualityComparer<T>.Default.Equals(lastInsertId, d))
            {
                SetCacheInfo(lastInsertId, obj);
            }
            return lastInsertId;
        }

        /// <summary>
        /// 插入数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="li"></param>
        /// <param name="extTableName"></param>
        /// <returns>受影响行数</returns>
        public int Insert<T>(IList<T> li, string extTableName = null)
        {
            int affectedRows = 0;
            if (li == null || li.Count == 0) return -1;
            string sql = MappingInfo.GetSqlStatementByType(typeof(T), "Insert", extTableName);

            List<string> paramNames = new List<string>();
            foreach (Match m in REGEX_GET_PARAM.Matches(sql))
                paramNames.Add(m.Value.Substring(1));

            sql = REGEX_GET_PARAM.Replace(sql, "$1#");//为所有参数加入#号
            StringBuilder sb = new StringBuilder(sql);

            string values = sql.Substring(sql.IndexOf(" values", StringComparison.CurrentCultureIgnoreCase) + 7);

            IDictionary<string, Object> param = new Dictionary<string, Object>();
            for (int i = 0; i < li.Count; i++)
            {
                if (sb.ToString().Length > 100000) //限制sql字符数
                {
                    affectedRows += _dao.Execute(sb.ToString(), param);

                    sb = new StringBuilder(sql);
                    param = new Dictionary<string, Object>();

                    sb.Replace("#", i.ToString());
                }
                else if (i == 0)
                {
                    sb.Replace("#", i.ToString());
                }
                else
                {
                    sb.AppendLine(",")
                      .Append(values.Replace("#", i.ToString()));
                }

                foreach (string propname in paramNames)
                {
                    param.Add(propname + i,
                        Context.Reflection.GetData(li[i], propname));
                }
            }

            if (sb.ToString().Length > 0)
            {
                affectedRows += _dao.Execute(sb.ToString(), param);
            }

            return affectedRows;
        }


        /// <summary>
        /// 插入数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="li"></param>
        /// <param name="extTableName"></param>
        /// <returns>受影响行数</returns>
        public async Task<int> InsertAsync<T>(IList<T> li, string extTableName = null)
        {
            int affectedRows = 0;
            if (li == null || li.Count == 0) return -1;
            string sql = MappingInfo.GetSqlStatementByType(typeof(T), "Insert", extTableName);

            List<string> paramNames = new List<string>();
            foreach (Match m in REGEX_GET_PARAM.Matches(sql))
                paramNames.Add(m.Value.Substring(1));

            sql = REGEX_GET_PARAM.Replace(sql, "$1#");//为所有参数加入#号
            StringBuilder sb = new StringBuilder(sql);

            string values = sql.Substring(sql.IndexOf(" values", StringComparison.CurrentCultureIgnoreCase) + 7);

            IDictionary<string, Object> param = new Dictionary<string, Object>();
            for (int i = 0; i < li.Count; i++)
            {
                if (sb.ToString().Length > 100000) //限制sql字符数
                {
                    affectedRows += await _dao.ExecuteAsync(sb.ToString(), param);

                    sb = new StringBuilder(sql);
                    param = new Dictionary<string, Object>();

                    sb.Replace("#", i.ToString());
                }
                else if (i == 0)
                {
                    sb.Replace("#", i.ToString());
                }
                else
                {
                    sb.AppendLine(",")
                      .Append(values.Replace("#", i.ToString()));
                }

                foreach (string propname in paramNames)
                {
                    param.Add(propname + i,
                        Context.Reflection.GetData(li[i], propname));
                }
            }

            if (sb.ToString().Length > 0)
            {
                affectedRows += await _dao.ExecuteAsync(sb.ToString(), param);
            }

            return affectedRows;
        }
        #endregion


        #region 修改数据
        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName"></param>
        /// <returns></returns>
        public bool Update(object obj, string extTableName = null)
        {
            if (obj == null) return false;

            SetCacheInfo(obj);

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Update", extTableName);
            return _dao.Execute(sql, obj) == 1;
        }
        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="extTableName"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(object obj, string extTableName = null)
        {
            if (obj == null) return false;

            SetCacheInfo(obj);

            string sql = MappingInfo.GetSqlStatementByType(obj.GetType(), "Update", extTableName);
            return await _dao.ExecuteAsync(sql, obj) == 1;
        }

        /// <summary>
        /// 批量修改数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="li"></param>
        /// <param name="extTableName"></param>
        /// <returns>受影响行数</returns>
        public int Update<T>(IList<T> li, string extTableName = null)
        {
            if (li == null || li.Count == 0) return -1;

            SetCacheInfo(li);

            string sql = MappingInfo.GetSqlStatementByType(li[0].GetType(), "Update", extTableName);

            List<string> paramNames = new List<string>();
            foreach (Match m in REGEX_GET_PARAM.Matches(sql))
                paramNames.Add(m.Value.Substring(1));

            sql = REGEX_GET_PARAM.Replace(sql, "$1#");//为所有参数加入#号
            StringBuilder sb = new StringBuilder();

            IDictionary<string, Object> param = new Dictionary<string, Object>(li.Count * paramNames.Count);
            for (int i = 0; i < li.Count; i++)
            {
                sb.Append(sql.Replace("#", i.ToString())).AppendLine(";");
                foreach (string propname in paramNames)
                {
                    param.Add(propname + i,
                        Context.Reflection.GetData(li[i], propname));
                }
            }

            return _dao.Execute(sb.ToString(), param);
        }

        /// <summary>
        /// 批量修改数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="li"></param>
        /// <param name="extTableName"></param>
        /// <returns>受影响行数</returns>
        public async Task<int> UpdateAsync<T>(IList<T> li, string extTableName = null)
        {
            if (li == null || li.Count == 0) return -1;

            SetCacheInfo(li);

            string sql = MappingInfo.GetSqlStatementByType(typeof(T), "Update", extTableName);

            List<string> paramNames = new List<string>();
            foreach (Match m in REGEX_GET_PARAM.Matches(sql))
                paramNames.Add(m.Value.Substring(1));

            sql = REGEX_GET_PARAM.Replace(sql, "$1#");//为所有参数加入#号
            StringBuilder sb = new StringBuilder();

            IDictionary<string, Object> param = new Dictionary<string, Object>(li.Count * paramNames.Count);
            for (int i = 0; i < li.Count; i++)
            {
                sb.Append(sql.Replace("#", i.ToString())).AppendLine(";");
                foreach (string propname in paramNames)
                {
                    param.Add(propname + i,
                        Context.Reflection.GetData(li[i], propname));
                }
            }
            return await _dao.ExecuteAsync(sb.ToString(), param);
        }


        /// <summary>
        /// 修改数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="di"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public int Update<T>(System.Collections.IDictionary di, QueryInfo<T> info)
        {
            bool hasId = false;
            Type type = typeof(T);
            string primaryKey = GetPrimaryKey(type);
            foreach (string key in info.Parameters.Keys)
            {
                if ((String.Compare(key, primaryKey, true) == 0))
                {
                    hasId = true;
                    DeleteCacheInfo(type, info.Parameters[key]);
                }
            }
            if (IsCacheReadWrite(type) != null && !hasId)
            {
                throw new ArgumentException("该表格有加入缓存读写，但当前查询信息未包括主键字段！");
            }

            string update = info.GetSQLPartialUpdate(di);
            CheckNoParams(update, info.Parameters);

            return _dao.Execute(update, info.Parameters);
        }


        /// <summary>
        /// 修改数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="di"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<int> UpdateAsync<T>(System.Collections.IDictionary di, QueryInfo<T> info)
        {
            bool hasId = false;
            Type type = typeof(T);
            string primaryKey = GetPrimaryKey(type);
            foreach (string key in info.Parameters.Keys)
            {
                if ((String.Compare(key, primaryKey, true) == 0))
                {
                    hasId = true;
                    DeleteCacheInfo(type, info.Parameters[key]);
                }
            }
            if (IsCacheReadWrite(type) != null && !hasId)
            {
                throw new ArgumentException("该表格有加入缓存读写，但当前查询信息未包括主键字段！");
            }

            string update = info.GetSQLPartialUpdate(di);
            CheckNoParams(update, info.Parameters);

            return await _dao.ExecuteAsync(update, info.Parameters);
        }
        #endregion


        #region 直接执行操作
        /// <summary>
        /// 执行sql（注：有加入缓存读写的表格不可以使用该方法）
        /// </summary>
        /// <param name="mapSql"></param>
        /// <param name="param">支持Dictionary类型</param>
        /// <returns></returns>
        public int Execute(string mapSql, IDictionary<string, object> param)
        {
            if (mapSql.IndexOf(' ') > 0)
                CheckSqlInject(mapSql);

            string sql = StatementParser.ParseDynamicSql(mapSql, param);
            CheckNoParams(sql, param);
            //if (sql.IndexOf(";") > 0)
            //    sql = sql.Replace("\r\n", " ");

            //_dao.TxBegin();
            return _dao.Execute(sql, param);
        }

        /// <summary>
        /// 执行sql（注：有加入缓存读写的表格不可以使用该方法）
        /// </summary>
        /// <param name="mapSql"></param>
        /// <param name="param">支持Dictionary类型</param>
        /// <returns></returns>
        public async Task<int> ExecuteAsync(string mapSql, IDictionary<string, object> param)
        {
            if (mapSql.IndexOf(' ') > 0)
                CheckSqlInject(mapSql);

            string sql = StatementParser.ParseDynamicSql(mapSql, param);
            CheckNoParams(sql, param);
            //if (sql.IndexOf(";") > 0)
            //    sql = sql.Replace("\r\n", " ");

            //_dao.TxBegin();
            return await _dao.ExecuteAsync(sql, param);
        }

        /// <summary>
        /// 执行sql（注：有加入缓存读写的表格不可以使用该方法）
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public int Execute(QueryInfo info)
        {
            if (IsCacheReadWrite(info.MappingType.GetType()) != null)
            {
                throw new ArgumentException("该表格有加入缓存读写，无法使用该方法！");
            }
            GetDynamicOrDefaultSql(info);
            return _dao.Execute(info);
        }

        /// <summary>
        /// 执行sql（注：有加入缓存读写的表格不可以使用该方法）
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<int> ExecuteAsync(QueryInfo info)
        {
            if (IsCacheReadWrite(info.MappingType.GetType()) != null)
            {
                throw new ArgumentException("该表格有加入缓存读写，无法使用该方法！");
            }
            GetDynamicOrDefaultSql(info);
            return await _dao.ExecuteAsync(info);
        }
        #endregion


        #region 查询操作

        /// <summary>
        /// 单一属性快捷查找
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="prop"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public IEnumerable<T> Select<T>(System.Linq.Expressions.Expression<Func<T, object>> prop, object value)
        {
            QueryInfo<T> info = new QueryInfo<T>()
               .AddParam(prop, value);
            GetDynamicOrDefaultSql(info);

            return _dao.Query<T>(info);
        }

        /// <summary>
        /// 单一属性快捷查找
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="prop"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> SelectAsync<T>(System.Linq.Expressions.Expression<Func<T, object>> prop, object value)
        {
            QueryInfo<T> info = new QueryInfo<T>()
               .AddParam(prop, value);
            GetDynamicOrDefaultSql(info);

            return await _dao.QueryAsync<T>(info);
        }


        /// <summary>
        /// mapSql将检测配置节DB_ADAPTERS对应的key，动态构造并返回新的sql
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql">如SysUser.List，动态处理{criteria [condition]}</param>
        /// <param name="param">必须为IDictionary类型才进行动态处理。 若不存在key,则不加载语句!</param>
        /// <returns></returns>
        public IEnumerable<T> Select<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return _dao.Query<T>(sql, param);
        }

        /// <summary>
        /// mapSql将检测配置节DB_ADAPTERS对应的key，动态构造并返回新的sql
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql">如SysUser.List，动态处理{criteria [condition]}</param>
        /// <param name="param">必须为IDictionary类型才进行动态处理。 若不存在key,则不加载语句!</param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> SelectAsync<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return await _dao.QueryAsync<T>(sql, param);
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public IEnumerable<object> Select(QueryInfo info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.Query(info);
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<IEnumerable<object>> SelectAsync(QueryInfo info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QueryAsync(info);
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public IEnumerable<T> Select<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.Query<T>(info);
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<IEnumerable<T>> SelectAsync<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QueryAsync<T>(info);
        }

        /// <summary>
        /// 根据ID获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public T SelectById<T>(object id)
        {
            string sql = MappingInfo.GetMappingInfo<T>().SelectById;
            Type type = typeof(T);
            var table = IsCacheReadWrite(type);
            bool isExistsCache = true;
            if (table != null && table.IsCacheReadWrite)
            {
                string key = type.FullName + "#" + id;
                if (StackExchangeHelper.KeyExists(key))
                {
                    return StackExchangeHelper.Get<T>(key);
                }
                else
                {
                    isExistsCache = false;
                }
            }
            var data = _dao.QuerySingleOrDefault<T>(sql,
                    new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), id } }
                );
            if (!isExistsCache && data != null)
            {
                SetCacheInfo(data);
            }
            return data;
        }

        /// <summary>
        /// 根据ID获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<T> SelectByIdAsync<T>(object id)
        {
            string sql = MappingInfo.GetMappingInfo<T>().SelectById;
            Type type = typeof(T);
            var table = IsCacheReadWrite(type);
            bool isExistsCache = true;
            if (table != null && table.IsCacheReadWrite)
            {
                string key = type.FullName + "#" + id;
                if (StackExchangeHelper.KeyExists(key))
                {
                    return StackExchangeHelper.Get<T>(key);
                }
                else
                {
                    isExistsCache = false;
                }
            }
            var data = await _dao.QuerySingleOrDefaultAsync<T>(sql,
                    new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), id } }
                );
            if (!isExistsCache && data != null)
            {
                SetCacheInfo(data);
            }
            return data;
        }

        /// <summary>
        /// 根据ID获取数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public object SelectById(Type type, object id)
        {
            QueryInfo info = new QueryInfo(type)
            {
                CustomSQL = MappingInfo.GetMappingInfo(type).SelectById
            };
            info.AddParam(GetPrimaryKey(type), id);
            return _dao.Query(info.ToSQLString(), info.Parameters, type)
                .SingleOrDefault();
        }

        /// <summary>
        /// 根据ID获取数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<object> SelectByIdAsync(Type type, object id)
        {
            QueryInfo info = new QueryInfo(type)
            {
                CustomSQL = MappingInfo.GetMappingInfo(type).SelectById
            };
            info.AddParam(GetPrimaryKey(type), id);
            return (await _dao.QueryAsync(info.ToSQLString(), info.Parameters, type)).SingleOrDefault();
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public T SelectSingle<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return _dao.QuerySingle<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<T> SelectSingleAsync<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return await _dao.QuerySingleAsync<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public T SelectSingle<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.QuerySingle<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<T> SelectSingleAsync<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QuerySingleAsync<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public T SelectSingleOrDefault<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return _dao.QuerySingleOrDefault<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<T> SelectSingleOrDefaultAsync<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return await _dao.QuerySingleOrDefaultAsync<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public T SelectSingleOrDefault<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.QuerySingleOrDefault<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<T> SelectSingleOrDefaultAsync<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QuerySingleOrDefaultAsync<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public T SelectFirst<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return _dao.QueryFirst<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<T> SelectFirstAsync<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return await _dao.QueryFirstAsync<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public T SelectFirst<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.QueryFirst<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<T> SelectFirstAsync<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QueryFirstAsync<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public T SelectFirstOrDefault<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return _dao.QueryFirstOrDefault<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mapSql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<T> SelectFirstOrDefaultAsync<T>(string mapSql, object param)
        {
            CheckSqlInject(mapSql);
            string sql;
            if (param is string)
            {
                param = new Dictionary<string, object>() { { GetPrimaryKey(typeof(T)), param } };
                sql = StatementParser.ParseDynamicSql(mapSql, param as Dictionary<string, object>);
            }
            else
                sql = AddParamToSqlWhere(typeof(T), mapSql, ref param);

            return await _dao.QueryFirstOrDefaultAsync<T>(sql, param);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public T SelectFirstOrDefault<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.QueryFirstOrDefault<T>(info);
        }

        /// <summary>
        /// 获取单个数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<T> SelectFirstOrDefaultAsync<T>(QueryInfo<T> info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QueryFirstOrDefaultAsync<T>(info);
        }


        /// <summary>
        /// 查询数量
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public int SelectCount(QueryInfo info)
        {
            GetDynamicOrDefaultSql(info);
            return _dao.QueryCount(info);
        }

        /// <summary>
        /// 查询数量
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<int> SelectCountAsync(QueryInfo info)
        {
            GetDynamicOrDefaultSql(info);
            return await _dao.QueryCountAsync(info);
        }

        /// <summary>
        /// 查询数量
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="prop"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public int SelectCount<T>(System.Linq.Expressions.Expression<Func<T, object>> prop, object value)
        {
            QueryInfo<T> info = new QueryInfo<T>()
               .AddParam(prop, value);
            GetDynamicOrDefaultSql(info);

            return _dao.QueryCount(info);
        }

        /// <summary>
        /// 查询数量
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="prop"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<int> SelectCountAsync<T>(System.Linq.Expressions.Expression<Func<T, object>> prop, object value)
        {
            QueryInfo<T> info = new QueryInfo<T>()
               .AddParam(prop, value);
            GetDynamicOrDefaultSql(info);

            return await _dao.QueryCountAsync(info);
        }


        /// <summary>
        /// 返回指定页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public List<T> SelectList<T>(QueryInfo<T> info)
        {
            if (info.PageSize > 0)
                info.DoCount(-1);
            return Select(info).ToList();
        }

        /// <summary>
        /// 返回指定页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<List<T>> SelectListAsync<T>(QueryInfo<T> info)
        {
            if (info.PageSize > 0)
                info.DoCount(-1);
            return (await SelectAsync(info)).ToList();
        }

        /// <summary>
        /// 返回总数+分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public QueryInfo<T> SelectInfo<T>(QueryInfo<T> info)
        {
            info.DoCount(1);
            GetDynamicOrDefaultSql(info);
            _dao.QueryPaginate(info);
            return info;
        }

        /// <summary>
        /// 返回总数+分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<QueryInfo<T>> SelectInfoAsync<T>(QueryInfo<T> info)
        {
            info.DoCount(1);
            GetDynamicOrDefaultSql(info);
            await _dao.QueryPaginateAsync(info);
            return info;
        }

        /// <summary>
        /// 返回总数+分页数据
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public QueryInfo SelectInfo(QueryInfo info)
        {
            info.DoCount(1);
            GetDynamicOrDefaultSql(info);
            _dao.QueryPaginate(info);
            info.MappingType = null;
            return info;
        }

        /// <summary>
        /// 当TotalCount==1时 返回总数+分页数据
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<QueryInfo> SelectInfoAsync(QueryInfo info)
        {
            info.DoCount(1);
            GetDynamicOrDefaultSql(info);
            await _dao.QueryPaginateAsync(info);
            info.MappingType = null;
            return info;
        }



        /// <summary>
        /// 返回数据+是否有下一页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public QueryInfo<T> SelectInfoNextPage<T>(QueryInfo<T> info)
        {
            var pageSize = info.PageSize;
            info.PageSize++;
            info.DoCount(-1);
            GetDynamicOrDefaultSql(info);
            _dao.QueryPaginate(info);
            info.HasNextPage = info.List.Count > pageSize;
            if (info.HasNextPage == true)
                info.List = info.List.Take(pageSize).ToList();
            return info;
        }

        /// <summary>
        /// 返回数据+是否有下一页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        public async Task<QueryInfo<T>> SelectInfoNextPageAsync<T>(QueryInfo<T> info)
        {
            var pageSize = info.PageSize;
            info.PageSize++;
            info.DoCount(-1);
            GetDynamicOrDefaultSql(info);
            await _dao.QueryPaginateAsync(info);
            info.HasNextPage = info.List.Count > pageSize;
            if (info.HasNextPage == true)
                info.List = info.List.Take(pageSize).ToList();
            return info;
        }
        #endregion


        //public System.Data.DataTable SelectDataTable(string mapSql, object param)
        //{
        //    CheckSqlInject(mapSql);
        //    string sql = AddParamToSqlWhere(typeof(DataTable), mapSql, ref param);

        //    return _dao.QueryDataTable(sql, param);
        //}

        //public System.Data.DataTable SelectDataTable(QueryInfo info)
        //{
        //    GetDynamicOrDefaultSql(info);
        //    return _dao.QueryDataTable(info.ToSQLString(), info.Parameters);
        //}



        //public IEnumerable<T> Select<T>(string mapSql, System.Linq.Expressions.Expression<Func<T, bool>> where)
        //{
        //    CheckSqlInject(mapSql);
        //    string sql = _dao.MapStatement(mapSql);
        //    if (sql == null) { sql = mapSql = "*"; }
        //    if (sql == mapSql && sql.IndexOf("select ", StringComparison.InvariantCultureIgnoreCase) < 0 && sql.IndexOf(" from", StringComparison.InvariantCultureIgnoreCase) < 0)
        //    {
        //        sql = "select " + mapSql + " from " + QueryInfo.GetMappingInfo<T>().Table + " t0";
        //    }
        //    return _dao.Query<T>(sql,where);
        //}

        #region 私有方法
        /// <summary>
        /// 根据T创建select，结合param生成where语句
        /// </summary>
        string AddParamToSqlWhere(Type type, string mapSql, ref object param)
        {
            if (string.IsNullOrEmpty(mapSql))//类型获取
                return GetMappedOrDefaultSql(type);

            if (param != null)
            {
                QueryInfo info = new QueryInfo();//添加当前参数，通过参数名可以控制语句类型：EQ，LK，GT等

                ////参数类型Anonymous对象？ 转换为IDictionary
                //if (!typeof(System.Collections.IDictionary).IsAssignableFrom(param.GetType()))
                //{
                //    var props = Dappers.Context.Reflection.GetHolder(param.GetType());
                //    Dictionary<string, Dappers.Context.GetHandler> getters = props.Getters;

                //    Dictionary<string, object> di = new Dictionary<string, object>(getters.Count);
                //    foreach(var getter in getters){
                //        di.Add(getter.Key,
                //            getter.Value(param) );
                //    }
                //    param = di;
                //}

                info.Parameters = (IDictionary<string, object>)param;
                if (!string.IsNullOrEmpty(mapSql))//重新映射
                    info.CustomSQL = mapSql;
                StatementParser.ParseDynamicSql(info);//配置语句 动态构造
                param = info.Parameters;//参数已被修改

                return info.ToSQLString() + info.ToOrderBy();
            }
            else
            {
                string sql = StatementParser.GetMappedStaticSql(mapSql);
                if (sql.Equals(mapSql) && sql.IndexOf(" ") < 0)
                    throw new ArgumentOutOfRangeException("无效的Sql配置项，请检查Key是否正确：" + mapSql);
                return sql;
            }
        }

        void CheckSqlInject(string sql)
        {
            if (sql != null && sql.IndexOf(' ') > 0)
            {
                if (HasSqlInject(sql))
                    throw new ArgumentException("无效的SQL语句!");
            }
        }

        static Regex regExSql = new Regex("create |alter |truncate |exec"
            , RegexOptions.Compiled | RegexOptions.IgnoreCase);//仅允许select 禁止sql中使用dba_/user_/v$等系统表

        /// <summary>
        /// 仅允许select操作，并禁止对oracle系统表select
        /// </summary>
        /// <param name="sArgs"></param>
        /// <returns></returns>
        static bool HasSqlInject(string sArgs)
        {
            if (sArgs != null && regExSql.IsMatch(sArgs))
                return true;
            return false;
        }

        private void GetDynamicOrDefaultSql(QueryInfo info)
        {
            if (info.NamedQuery == null)
            {
                if (string.IsNullOrEmpty(info.CustomSQL))//从Type获取SQL
                {
                    info.CustomSQL = GetMappedOrDefaultSql(info.GetMappingType());
                }
                else//已经制定SQL，动态化！
                {
                    StatementParser.ParseDynamicSql(info);
                }
            }
        }

        ///获取xml中配置的 User.Select语句， 或者根据对象的属性映射生成语句
        private string GetMappedOrDefaultSql(Type type)
        {
            if (type == null)
                throw new ArgumentNullException("MappingType", "QueryInfo未指定查询的对象类型!");

            string key = type.Name + ".Select";
            string sql = StatementParser.GetMappedStaticSql(key);
            if (sql.Equals(key))
                sql = (MappingInfo.GetMappingInfo(type).Select + "t");
            return sql;
        }


        private static readonly Regex REGEX_GET_PARAM = new Regex("(" + StatementParser.PREFIX + "\\w*)", RegexOptions.Multiline);

        /// <summary>
        /// update、delete语句必须提供参数才允许执行！
        /// </summary>
        private void CheckNoParams(string sql, IDictionary<string, object> param)
        {
            if (sql.IndexOf("delete from", StringComparison.CurrentCultureIgnoreCase) > -1 || sql.IndexOf(" set ", StringComparison.CurrentCultureIgnoreCase) > -1)
            {//delete,update
                if (param == null || param.Count == 0)
                    throw new DappersException("删除、更新语句必须至少提供一个参数！");
            }
        }

        #endregion

    }
}
